Ext.ns('Ext.ux.form');
/**
 * *
 * 
 * @class Ext.ux.form.DateTime *
 * @extends Ext.form.Field
 */
Ext.ux.form.DateTime = Ext.extend(Ext.form.Field, {
	/**
	 * *
	 * 
	 * @cfg {String/Object} defaultAutoCreate DomHelper element spec * Let
	 *      superclass to create hidden field instead of textbox. Hidden will be
	 *      submittend to server
	 */
	defaultAutoCreate : {
		tag : 'input',
		type : 'hidden'
	},
	/**
	 * *
	 * 
	 * @cfg {Number} timeWidth Width of time field in pixels (defaults to 100)
	 */
	timeWidth : 100,
	/**
	 * *
	 * 
	 * @cfg {String} dtSeparator Date - Time separator. Used to split date and
	 *      time (defaults to ' ' (space))
	 */
	dtSeparator : ' ',
	/**
	 * *
	 * 
	 * @cfg {String} hiddenFormat Format of datetime used to store value in
	 *      hidden field * and submitted to server (defaults to 'Y-m-d H:i:s'
	 *      that is mysql format)
	 */
	hiddenFormat : 'Y-m-d H:i:s',
	/**
	 * *
	 * 
	 * @cfg {Boolean} otherToNow Set other field to now() if not explicly filled
	 *      in (defaults to true)
	 */
	otherToNow : true,
	/**
	 * *
	 * 
	 * @cfg {Boolean} emptyToNow Set field value to now on attempt to set empty
	 *      value. * If it is true then setValue() sets value of field to
	 *      current date and time (defaults to false)
	 */
	/**
	 * *
	 * 
	 * @cfg {String} timePosition Where the time field should be rendered.
	 *      'right' is suitable for forms * and 'below' is suitable if the field
	 *      is used as the grid editor (defaults to 'right')
	 */
	timePosition : 'right',
	// valid values:'below', 'right'
	/**
	 * *
	 * 
	 * @cfg {String} dateFormat Format of DateField. Can be localized. (defaults
	 *      to 'm/y/d')
	 */
	dateFormat : 'm/d/y',
	/**
	 * *
	 * 
	 * @cfg {String} timeFormat Format of TimeField. Can be localized. (defaults
	 *      to 'g:i A')
	 */
	timeFormat : 'g:i A',
	/**
	 * *
	 * 
	 * @cfg {Object} dateConfig Config for DateField constructor.
	 */
	/**
	 * *
	 * 
	 * @cfg {Object} timeConfig Config for TimeField constructor.
	 */
	// {{{
	/**
	 * * private * creates DateField and TimeField and installs the necessary
	 * event handlers
	 */
	initComponent : function() {
		// call parent initComponent
		Ext.ux.form.DateTime.superclass.initComponent.call(this);
		// create DateField
		var dateConfig = Ext.apply({}, {
			id : this.id + '-date',
			format : this.dateFormat || Ext.form.DateField.prototype.format,
			width : this.timeWidth,
			selectOnFocus : this.selectOnFocus,
			listeners : {
				blur : {
					scope : this,
					fn : this.onBlur
				},
				focus : {
					scope : this,
					fn : this.onFocus
				}
			}
		}, this.dateConfig);
		this.df = new Ext.form.DateField(dateConfig);
		this.df.ownerCt = this;
		delete(this.dateFormat);
		// create TimeField
		var timeConfig = Ext.apply({}, {
			id : this.id + '-time',
			format : this.timeFormat || Ext.form.TimeField.prototype.format,
			width : this.timeWidth,
			selectOnFocus : this.selectOnFocus,
			listeners : {
				blur : {
					scope : this,
					fn : this.onBlur
				},
				focus : {
					scope : this,
					fn : this.onFocus
				}
			}
		}, this.timeConfig);
		this.tf = new Ext.form.TimeField(timeConfig);
		this.tf.ownerCt = this;
		delete(this.timeFormat);
		// relay events
		this.relayEvents(this.df, ['focus', 'specialkey', 'invalid', 'valid']);
		this.relayEvents(this.tf, ['focus', 'specialkey', 'invalid', 'valid']);
	},
	onRender : function(ct, position) {
		// don't run more than once
		if (this.isRendered) {
			return;
		}
		// render underlying hidden field
		Ext.ux.form.DateTime.superclass.onRender.call(this, ct, position);
		// render DateField and TimeField
		// create bounding table
		var t;
		if ('below' === this.timePosition || 'bellow' === this.timePosition) {
			t = Ext.DomHelper.append(ct, {
				tag : 'table',
				style : 'border-collapse:collapse',
				children : [{
					tag : 'tr',
					children : [{
						tag : 'td',
						style : 'padding-bottom:1px',
						cls : 'ux-datetime-date'
					}]
				}, {
					tag : 'tr',
					children : [{
						tag : 'td',
						cls : 'ux-datetime-time'
					}]
				}]
			}, true);
		} else {
			t = Ext.DomHelper.append(ct, {
				tag : 'table',
				style : 'border-collapse:collapse',
				children : [{
					tag : 'tr',
					children : [{
						tag : 'td',
						style : 'padding-right:4px',
						cls : 'ux-datetime-date'
					}, {
						tag : 'td',
						cls : 'ux-datetime-time'
					}]
				}]
			}, true);
		}
		this.tableEl = t;
		// this.wrap = t.wrap({cls:'x-form-field-wrap'});
		this.wrap = t.wrap();
		this.wrap.on("mousedown", this.onMouseDown, this, {
			delay : 10
		});
		// render DateField & TimeField
		this.df.render(t.child('td.ux-datetime-date'));
		this.tf.render(t.child('td.ux-datetime-time'));
		// workaround for IE trigger misalignment bug
		if (Ext.isIE && Ext.isStrict) {
			t.select('input').applyStyles({
				top : 0
			});
		}
		this.on('specialkey', this.onSpecialKey, this);
		this.df.el.swallowEvent(['keydown', 'keypress']);
		this.tf.el.swallowEvent(['keydown', 'keypress']);
		// create icon for side invalid errorIcon
		if ('side' === this.msgTarget) {
			var elp = this.el.findParent('.x-form-element', 10, true);
			this.errorIcon = elp.createChild({
				cls : 'x-form-invalid-icon'
			});
			this.df.errorIcon = this.errorIcon;
			this.tf.errorIcon = this.errorIcon;
		}
		// setup name for submit
		this.el.dom.name = this.hiddenName || this.name || this.id;
		// prevent helper fields from being submitted
		this.df.el.dom.removeAttribute("name");
		this.tf.el.dom.removeAttribute("name");
		// we're rendered flag
		this.isRendered = true;
		// update hidden field
		this.updateHidden();
	},
	// eo function onRender
	// }}}
	// {{{
	/** * private */

	adjustSize : Ext.BoxComponent.prototype.adjustSize,
	// }}}
	// {{{
	/** * private */

	alignErrorIcon : function() {
		this.errorIcon.alignTo(this.tableEl, 'tl-tr', [2, 0]);
	},
	// }}}
	// {{{
	/** * private initializes internal dateValue */

	initDateValue : function() {
		this.dateValue = this.otherToNow ? new Date() : new Date(1970, 0, 1, 0,
				0, 0);
	},
	// }}}
	// {{{
	/** * Calls clearInvalid on the DateField and TimeField */

	clearInvalid : function() {
		this.df.clearInvalid();
		this.tf.clearInvalid();
	},
	// eo function clearInvalid
	// }}}
	/**
	 * *
	 * 
	 * @private * called from Component::destroy. * Destroys all elements and
	 *          removes all listeners we've created.
	 */

	beforeDestroy : function() {
		if (this.isRendered) {
			// this.removeAllListeners();
			this.wrap.removeAllListeners();
			this.wrap.remove();
			this.tableEl.remove();
			this.df.destroy();
			this.tf.destroy();
		}
	},
	// eo function beforeDestroy
	// {{{
	/**
	 * * Disable this component. *
	 * 
	 * @return {Ext.Component} this
	 */

	disable : function() {
		if (this.isRendered) {
			this.df.disabled = this.disabled;
			this.df.onDisable();
			this.tf.onDisable();
		}
		this.disabled = true;
		this.df.disabled = true;
		this.tf.disabled = true;
		this.fireEvent("disable", this);
		return this;
	},
	// eo function disable
	// }}}
	// {{{
	/**
	 * * Enable this component. *
	 * 
	 * @return {Ext.Component} this
	 */

	enable : function() {
		if (this.rendered) {
			this.df.onEnable();
			this.tf.onEnable();
		}
		this.disabled = false;
		this.df.disabled = false;
		this.tf.disabled = false;
		this.fireEvent("enable", this);
		return this;
	},
	// eo function enable
	// }}}
	// {{{
	/** * private Focus date filed */

	focus : function() {
		this.df.focus();
	},
	// eo function focus
	// }}}
	// {{{
	/** * private */

	getPositionEl : function() {
		return this.wrap;
	},
	// }}}
	// {{{
	/** * private */

	getResizeEl : function() {
		return this.wrap;
	},
	// }}}
	// {{{
	/**
	 * *
	 * 
	 * @return {Date/String} Returns value of this field
	 */

	getValue : function() {
		// create new instance of
		// date
		return this.dateValue ? new Date(this.dateValue) : '';
	},
	// eo function initComponent
	// }}}
	// {{{
	/**
	 * * private * Renders underlying DateField and TimeField and provides a
	 * workaround for side error icon bug
	 */
	// eo function getValue
	// }}}
	// {{{
	/**
	 * *
	 * 
	 * @return {Boolean} true = valid, false = invalid * private Calls isValid
	 *         methods of underlying DateField and TimeField and returns the
	 *         result
	 */
	isValid : function() {
		return this.df.isValid() && this.tf.isValid();
	},
	// eo function isValid
	// }}}
	// {{{
	/**
	 * * Returns true if this component is visible *
	 * 
	 * @return {boolean}
	 */
	isVisible : function() {
		return this.df.rendered && this.df.getActionEl().isVisible();
	},
	onBlur : function(f) {
		// called by both DateField and TimeField blur events
		// revert focus to previous field if clicked in between
		if (this.wrapClick) {
			f.focus();
			this.wrapClick = false;
		}
		// update underlying value
		if (f === this.df) {
			this.updateDate();
		} else {
			this.updateTime();
		}
		this.updateHidden();
		// fire events later

		(function() {
			if (!this.df.hasFocus && !this.tf.hasFocus) {
				var v = this.getValue();
				if (String(v) !== String(this.startValue)) {
					this.fireEvent("change", this, v, this.startValue);
				}
				this.hasFocus = false;
				this.fireEvent('blur', this);
			}
		}).defer(100, this);
	},
	// eo function onBlur
	// }}}
	// {{{
	/** * private Handles focus event */

	onFocus : function() {
		if (!this.hasFocus) {
			this.hasFocus = true;
			this.startValue = this.getValue();
			this.fireEvent("focus", this);
		}
	},
	// }}}
	// {{{
	/**
	 * * private Just to prevent blur event when clicked in the middle of fields
	 */

	onMouseDown : function(e) {
		if (!this.disabled) {
			this.wrapClick = 'td' === e.target.nodeName.toLowerCase();
		}
	},
	// }}}
	// {{{
	/**
	 * * private * Handles Tab and Shift-Tab events
	 */

	onSpecialKey : function(t, e) {
		var key = e.getKey();
		if (key === e.TAB) {
			if (t === this.df && !e.shiftKey) {
				e.stopEvent();
				this.tf.focus();
			}
			if (t === this.tf && e.shiftKey) {
				e.stopEvent();
				this.df.focus();
			}
		}
		// otherwise it
		// misbehaves in
		// editor grid
		if (key === e.ENTER) {
			this.updateValue();
		}
	},
	// eo function
	// onSpecialKey
	// }}}
	// {{{
	/**
	 * * private Sets the value of DateField
	 */

	// eo function isVisible
	// }}}
	// {{{
	/** * private Handles blur event */
	setDate : function(date) {
		this.df.setValue(date);
	},
	// eo
	// function
	// setDate
	// }}}
	// {{{
	/**
	 * * private Sets the value of TimeField
	 */

	setTime : function(date) {
		this.tf.setValue(date);
	},

	// eo
	// function
	// setTime
	// }}}
	// {{{

	/**
	 * * private * Sets correct sizes of underlying DateField and TimeField *
	 * With workarounds for IE bugs
	 */
	setSize : function(w, h) {
		if (!w) {
			return;
		}
		if ('below' === this.timePosition) {
			this.df.setSize(w, h);
			this.tf.setSize(w, h);
			if (Ext.isIE) {
				this.df.el.up('td').setWidth(w);
				this.tf.el.up('td').setWidth(w);
			}
		} else {
			this.df.setSize(w - this.timeWidth - 4, h);
			this.tf.setSize(this.timeWidth, h);
			if (Ext.isIE) {
				this.df.el.up('td').setWidth(w - this.timeWidth - 4);
				this.tf.el.up('td').setWidth(this.timeWidth);
			}
		}
	}, // eo
	// function
	// setSize
	// }}}
	// {{{
	/**
	 * *
	 * 
	 * @param {Mixed}
	 *            val Value to set * Sets the value of this field
	 */
	setValue : function(val) {
		if (!val && true === this.emptyToNow) {
			this.setValue(new Date());
			return;
		} else if (!val) {
			this.setDate('');
			this.setTime('');
			this.updateValue();
			return;
		}
		if ('number' === typeof val) {
			val = new Date(val);
		}
		val = val ? val : new Date(1970, 0, 1, 0, 0, 0);
		var da, time;
		if (val instanceof Date) {
			this.setDate(val);
			this.setTime(val);
			this.dateValue = new Date(val);
		} else {
			da = val.split(this.dtSeparator);
			this.setDate(da[0]);
			if (da[1]) {
				if (da[2]) {
					// add am/pm partback to time
					da[1] += da[2];
				}
				this.setTime(da[1]);
			}
		}
		this.updateValue();
	}, // eo
	// function
	// setValue
	// }}}
	// {{{
	/**
	 * * Hide or show this component by boolean *
	 * 
	 * @return {Ext.Component} this
	 */
	setVisible : function(visible) {
		if (visible) {
			this.df.show();
			this.tf.show();
		} else {
			this.df.hide();
			this.tf.hide();
		}
		return this;
	},
	// eo
	// function
	// setVisible
	// }}}
	// {{{
	show : function() {
		return this.setVisible(true);
	},
	// eo
	// function
	// show
	// }}}
	// {{{
	hide : function() {
		return this.setVisible(false);
	},
	// eo
	// function
	// hide
	// }}}
	// {{{
	/**
	 * * private Updates the date part
	 */
	updateDate : function() {
		var d = this.df.getValue();
		if (d) {
			if (!(this.dateValue instanceof Date)) {
				this.initDateValue();
				if (!this.tf.getValue()) {
					this.setTime(this.dateValue);
				}
			}
			this.dateValue.setMonth(0);
			// because
			// of
			// leap
			// years
			this.dateValue.setFullYear(d.getFullYear());
			this.dateValue.setMonth(d.getMonth());
			this.dateValue.setDate(d.getDate());
		} else {
			this.dateValue = '';
			this.setTime('');
		}
	},
	// eo
	// function
	// updateDate
	// }}}
	// {{{
	/**
	 * * private * Updates the time part
	 */
	updateTime : function() {
		var t = this.tf.getValue();
		if (t && !(t instanceof Date)) {
			t = Date.parseDate(t, this.tf.format);
		}
		if (t && !this.df.getValue()) {
			this.initDateValue();
			this.setDate(this.dateValue);
		}
		if (this.dateValue instanceof Date) {
			if (t) {
				this.dateValue.setHours(t.getHours());
				this.dateValue.setMinutes(t.getMinutes());
				this.dateValue.setSeconds(t.getSeconds());
			} else {
				this.dateValue.setHours(0);
				this.dateValue.setMinutes(0);
				this.dateValue.setSeconds(0);
			}
		}
	},
	// eo
	// function
	// updateTime
	// }}}
	// {{{
	/**
	 * * private Updates the underlying hidden field value
	 */
	updateHidden : function() {
		if (this.isRendered) {
			var value = this.dateValue instanceof Date ? this.dateValue
					.format(this.hiddenFormat) : '';
			this.el.dom.value = value;
		}
	},
	// }}}
	// {{{
	/**
	 * * private Updates all of Date, Time and Hidden
	 */

	updateValue : function() {
		this.updateDate();
		this.updateTime();
		this.updateHidden();
		return;
	},
	// eo
	// function
	// updateValue
	// }}}
	// {{{
	/**
	 * *
	 * 
	 * @return {Boolean} true = valid, false = invalid * callse validate methods
	 *         of DateField and TimeField
	 */
	validate : function() {
		return this.df.validate() && this.tf.validate();
	},
	// eo
	// function
	// validate
	// }}}
	// {{{
	/**
	 * * Returns renderer suitable to render this field *
	 * 
	 * @param {Object}
	 *            Column model config
	 */
	renderer : function(field) {
		var format = field.editor.dateFormat
				|| Ext.ux.form.DateTime.prototype.dateFormat;
		format += ' '
				+ (field.editor.timeFormat || Ext.ux.form.DateTime.prototype.timeFormat);
		var renderer = function(val) {
			var retval = Ext.util.Format.date(val, format);
			return retval;
		};
		return renderer;
	}
// eo function renderer
// }}}
});
// eo extend register
Ext.reg('xdatetime', Ext.ux.form.DateTime);
